////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2008, 2009 The Mist project                                  //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the implementation of the CodeStream methods and related functions.
///

#include "codestream.hpp"

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include <climits>

#include "common/assert.hpp"

////////////////////////////////////////////////////////////////////////////////
// Function Implementations                                                   //
////////////////////////////////////////////////////////////////////////////////

CodeStream::CodeStream(ostream& stream, ushort indentSize) : _stream(stream), _newline(true), _indentation(0), _indentSize(indentSize) {
} // intentionally empty

CodeStream& indent(CodeStream& stream) {
	assert(stream._indentation < UINT_MAX);
	
	stream._indentation ++;
	
	return stream;
}

CodeStream& unindent(CodeStream& stream) {
	assert(stream._indentation > 0);
	
	stream._indentation --;
	
	return stream;
}

CodeStream& CodeStream::operator<<(const char* data) {
	for (uint i = 0; data[i] != '\0'; ++i)
		put(data[i]);
	return *this;
}

CodeStream& CodeStream::operator<<(string data) {
	for (uint i = 0; i < data.size(); ++i)
		put(data[i]);
	return *this;
}

CodeStream& CodeStream::operator<<(char c) {
	put(c);
	return *this;
}

CodeStream& CodeStream::put(char c) {
	maybe_indent();
	_stream << c;
	if (c == '\n')
		_newline = true;
	return *this;
}

CodeStream& CodeStream::operator<< (ostream& ( *pf )(ostream&)) {
	assert(pf != NULL);
	
	if ((ostream& (*)(ostream&))pf == (ostream& (*)(ostream&))endl)
		_newline = true;
	_stream << pf;
	return *this;
}

CodeStream& CodeStream::operator<< (CodeStream& ( *pf )(CodeStream&)) {
	assert(pf != NULL);
	
	return pf(*this);
}

ushort CodeStream::indent_size() const {
	return _indentSize;
}

void CodeStream::maybe_indent() {
	if (_newline) {
		_stream << string(_indentSize * _indentation, ' ');
		_newline = false;
	}
}
